package com.zxp.web.sys_user.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.zxp.web.VO.ResultUtils;
import com.zxp.web.VO.ResultVO;
import com.zxp.web.constants.Constants;
import com.zxp.web.jwt.JwtUtils;
import com.zxp.web.sys_menu.entity.SysMenu;
import com.zxp.web.sys_menu.service.SysMenuService;
import com.zxp.web.sys_user.entity.*;
import com.zxp.web.sys_user.service.SysUserService;
import com.zxp.web.sys_user_role.entity.SysUserRole;
import com.zxp.web.sys_user_role.service.SysUserRoleService;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;


/**
 * @author MasterZ
 * @Date 2025/10/1 20:56
 */
@RestController
@Slf4j
@RequestMapping("/api/sysUser")
public class SysUserController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private DefaultKaptcha defaultKaptcha;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private SysMenuService sysMenuService;
    @Value("${sys.loginCode}")
    private boolean loginCode;//登陆时是否需要填验证码
    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    PasswordEncoder passwordEncoder;

    //新增用户
    @PostMapping("/add")
    @PreAuthorize("hasAuthority('sys:user:add')")
    public ResultVO add(@RequestBody SysUser sysUser) {
        sysUser.setPassword(passwordEncoder.encode(sysUser.getPassword()));
        sysUserService.saveUser(sysUser);
        return ResultUtils.success("添加成功！");
    }

    //编辑用户
    @PutMapping
    @PreAuthorize("hasAuthority('sys:user:edit')")
    public ResultVO update(@RequestBody SysUser sysUser) {
        sysUserService.editUser(sysUser);
        return ResultUtils.success("编辑成功！");
    }

    //根据userId删除用户
    @DeleteMapping("/{userId}")
    @PreAuthorize("hasAuthority('sys:user:del')")
    public ResultVO delete(@PathVariable("userId") Long userId) {
        sysUserService.deleteUser(userId);
        return ResultUtils.success();
    }

    //查询用户列表
    @GetMapping("/getList")
    public ResultVO list(SysUserParam sysUserParam) {
        IPage<SysUser> page = new Page<>(sysUserParam.getCurrentPage(), sysUserParam.getPageSize());
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(sysUserParam.getNickName())) {
            queryWrapper.lambda().like(SysUser::getNickName, sysUserParam.getNickName());
        }
        if (StringUtils.isNotEmpty(sysUserParam.getPhone())) {
            queryWrapper.lambda().like(SysUser::getPhone, sysUserParam.getPhone());
        }
        queryWrapper.lambda().orderByDesc(SysUser::getCreateTime);
        IPage<SysUser> list = sysUserService.page(page, queryWrapper);
        return ResultUtils.success("查询成功", list);

    }

    //根据用户ID查询角色列表
    @GetMapping("/getRoleList")
    public ResultVO getRoleList(Long userId) {
        QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysUserRole::getUserId, userId);
        List<SysUserRole> list = sysUserRoleService.list(queryWrapper);
        //角色ID
        ArrayList<Long> roleList = new ArrayList<>();
        Optional.ofNullable(list).orElse(new ArrayList<>())
                .forEach(item -> roleList.add(item.getRoleId()));
        return ResultUtils.success("查询成功", roleList);
    }

    //重置密码
    @PostMapping("/resetPassword")
    @PreAuthorize("hasAuthority('sys:user:restPwd')")
    public ResultVO resetPassword(@RequestBody SysUser sysUser) {
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>(sysUser);
        updateWrapper.lambda().eq(SysUser::getUserId, sysUser.getUserId())
                .set(SysUser::getPassword, passwordEncoder.encode(Constants.DEFAULT_USER_PASSWORD));
        if (sysUserService.update(updateWrapper)) {
            return ResultUtils.success();
        }
        return ResultUtils.error();
    }

    @GetMapping("/checkUserName")
    public ResultVO checkNickName(String userName) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysUser::getUsername, userName);
        long count = sysUserService.count(queryWrapper);
        return ResultUtils.success("查询成功", count >= 1);
    }

    //直接返回图片
    @GetMapping("/getKaptcha")
    public void getKaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
        byte[] captchaChallengeAsJpeg;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            // 生产验证码字符串并保存到session中
            String createText = defaultKaptcha.createText();
            request.getSession().setAttribute("code", createText);
            log.info("验证码值：{}", request.getSession().getAttribute("code"));
            // 使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
            BufferedImage challenge = defaultKaptcha.createImage(createText);
            ImageIO.write(challenge, "jpg", jpegOutputStream);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        // 定义response输出类型为image/jpeg类型，使用response输出流输出图片的byte数组
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }

    //通过ResultVO的data返回图片
    @PostMapping("/getImage")
    public ResultVO getImage(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String text = defaultKaptcha.createText();
        System.out.println("验证码：" + text);
        session.setAttribute("code", text);
        BufferedImage bufferedImage = defaultKaptcha.createImage(text);
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            try {
                ImageIO.write(bufferedImage, "jpg", outputStream);
                String encode = Base64.encodeBase64String(outputStream.toByteArray());
                String captchaBase64 = "data:image/jpeg;base64," + encode.replaceAll("\r\n", "")
                        .replaceAll("\n", "").replace("\r", "");
                return ResultUtils.success("获取成功！", captchaBase64);
            } catch (IOException e) {
                return ResultUtils.error(e.getMessage());
            }
        } catch (IOException e) {
            log.info(e.getMessage());
        }
        return ResultUtils.error();
    }

    @PostMapping("/login")
    public ResultVO login(HttpServletRequest request, @RequestBody LoginParam loginParam) {
        //验证码
        if (loginCode) {
            HttpSession session = request.getSession();
            String code = (String) session.getAttribute(Constants.VERIFY_CODE_ID_IN_SESSION);
            if (StringUtils.isEmpty(code)) {
                return ResultUtils.error("验证码已过期！");
            }
            String paramCode = loginParam.getCode();
            if (!code.equals(paramCode)) {
                return ResultUtils.error("验证码错误！");
            }
        }
        //springSecurity登陆
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginParam.getUsername(), loginParam.getPassword());
        Authentication authenticate = authenticationManager.authenticate(token);
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        SysUser sysUser = (SysUser) authenticate.getPrincipal();
        //传统登陆
//        String username = loginParam.getUsername();
//        String password = loginParam.getPassword();
//        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda().eq(SysUser::getUsername, username).eq(SysUser::getPassword, password);
//        SysUser sysUser = sysUserService.getOne(queryWrapper);
//        if (sysUser == null) {
//            return ResultUtils.error("用户名或密码错误！");
//        }
        //返回用户信息和token
//        session.setAttribute("loginUser", sysUser);
        LoginVO loginVO = new LoginVO();
        loginVO.setUserId(sysUser.getUserId());
        loginVO.setNickName(sysUser.getNickName());
        Map<String, String> map = new HashMap<>();
        map.put("userId", Long.toString(sysUser.getUserId()));
        map.put("username", sysUser.getUsername());
        String jwtToken = jwtUtils.generateToken(map);
        loginVO.setToken(jwtToken);
        return ResultUtils.success("登陆成功", loginVO);
    }

    //修改密码
    @PostMapping("/updatePassword")
    public ResultVO updatePassword(@RequestBody UpdatePasswordParam updatePasswordParam) {
        SysUser user = sysUserService.getById(updatePasswordParam.getUserId());
//        if (!updatePasswordParam.getOldPassword().equals(user.getPassword())) {
//            return ResultUtils.error("旧密码不匹配");
//        }
        //springSecurity验证方式
        if (!passwordEncoder.matches(updatePasswordParam.getOldPassword(), user.getPassword())) {
            return ResultUtils.error("旧密码不匹配");
        }
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(SysUser::getUserId, user.getUserId()).set(SysUser::getPassword, updatePasswordParam.getNewPassword());
        updatePasswordParam.setNewPassword(passwordEncoder.encode(updatePasswordParam.getNewPassword()));
        if (sysUserService.update(updateWrapper)) {
            return ResultUtils.success("密码修改成功");
        }
        return ResultUtils.error();
    }

    //获取用户信息
    @GetMapping("/getUserInfo")
    public ResultVO getUserInfo(Long userId) {
        SysUser user = sysUserService.getById(userId);
        List<SysMenu> menus;
        //是否超级管理员
        if (StringUtils.isNotEmpty(user.getIsAdmin()) && Constants.IS_ADMIN.equals(user.getIsAdmin())) {
            menus = sysMenuService.list();
        } else {
            menus = sysMenuService.getMenuByUserId(userId);
        }
        //获取菜单表里的权限字符code
        List<String> codeList = Optional.ofNullable(menus).orElse(new ArrayList<>())
                .stream()
                .filter(item -> item != null && StringUtils.isNotEmpty(item.getCode()))
                .map(SysMenu::getCode)
                .toList();
        //设置返回值
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(userId);
        userInfo.setName(user.getNickName());
        userInfo.setPermissions(codeList.toArray());
        return ResultUtils.success("查询成功", userInfo);
    }

    //退出登陆
    @PostMapping("/logout")
    public ResultVO logout(HttpServletRequest request, HttpServletResponse response) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            new SecurityContextLogoutHandler().logout(request, response, authentication);
        }
        return ResultUtils.success();
    }
}
